package com.unitd.base.module.logistics.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.unitd.base.frame.enums.ResultEnum;
import com.unitd.base.frame.exception.LogisticsException;
import com.unitd.base.frame.file.ExcelUtils;
import com.unitd.base.frame.utils.BeanUtils;
import com.unitd.base.frame.utils.DateUtils;
import com.unitd.base.frame.utils.ListUtils;
import com.unitd.base.frame.utils.StringUtils;
import com.unitd.base.module.logistics.po.ExpressData;
import com.unitd.base.module.logistics.po.ExpressDetail;
import com.unitd.base.module.logistics.service.BatchExpressFileService;
import com.unitd.base.module.logistics.service.ExpressDetailService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 处理实际的上传的快递信息文件并调用相应的接口获取接口
 *
 * @author hudan
 * @version 1.0
 * @filename BatchExpressFileServiceImpl.java
 * @copyright www.unitd.com
 * @date 2019-02-11
 */
@Service
@Slf4j
public class BatchExpressFileServiceImpl implements BatchExpressFileService {

	@Autowired
	private ExpressDetailService expressDetailService;

	/**
	 * 根据导入的快递文件信息, 调用相应的接口获取物流详情后, 写入结果文件
	 *
	 * @param importFile 导入的需要查询的文件
	 */
	@Override
	public File importAndDealWithExcel(File importFile) {

		// 读取需要查询的excel文件内容
		Map<String, List<ExpressDetail>> dataMap = importData(importFile);

		// 遍历读取到的内容,并逐个写入excel文件
		File exportExcelFile = exportDataToExcel(importFile, dataMap);

		log.info("导入-转换数据-导出完成! 结果文件为: {}", exportExcelFile);
		return exportExcelFile;
	}

	/**
	 * 读取导入的excel文件内容, 只需要读取前面两列即可
	 *
	 * @param file excel文件
	 * @return 读取excel文件后的数据列表
	 */
	private Map<String, List<ExpressDetail>> importData(File file) {
		// 整个excel数据文件中的记录集合
		Map<String, List<ExpressDetail>> resultMap = Maps.newHashMap();

		Workbook workbook;
		try {
			if (ExcelUtils.isExcel2007(file.getPath())) {
				workbook = new XSSFWorkbook(new FileInputStream(file));
			} else {
				workbook = new HSSFWorkbook(new FileInputStream(file));
			}
		} catch (IOException e) {
			throw new LogisticsException(ResultEnum.READ_EXCEL_FILE_ERROR);
		}

		// 每一个sheet中数据行记录信息
		List<ExpressDetail> expressDetails;
		// 获取excel文件中,sheet的个数
		int sheetNum = workbook.getNumberOfSheets();

		// 遍历读取每一个sheet
		for (int m = 0; m < sheetNum; m++) {
			expressDetails = Lists.newArrayList();
			// 创建相应的Sheet
			Sheet sheet = workbook.getSheetAt(m);

			/* 读取每行数据(忽略第一行 表头) */
			// 获得总行数
			int rowNum = sheet.getLastRowNum();
			for (int i = 0; i <= rowNum; i++) {
				// 获取索引为i的行，以0开始
				Row row = sheet.getRow(i);
				if (i == 0) {
					continue;
				}
				if (row == null || row.getCell(0) == null) {
					break;
				}

				// 获取第i行的索引为0的单元格数据
				String expressCompany = row.getCell(0).getStringCellValue();
				String expressNo = row.getCell(1).getStringCellValue();

				if (StringUtils.isNull(expressCompany) && StringUtils.isNull(expressNo)) {
					break;
				}

				ExpressDetail expressDetail = new ExpressDetail(expressCompany, expressNo);
				expressDetails.add(expressDetail);
			}
			resultMap.put(sheet.getSheetName(), expressDetails);
		}

		try {
			workbook.close();
		} catch (IOException e) {
			throw new LogisticsException(ResultEnum.READ_EXCEL_FILE_ERROR);
		}
		return resultMap;
	}

	/**
	 * 将处理后的结果数据写入结果文件
	 *
	 * @param importFile 原始查询数据文件
	 * @param dataMap    结果数据
	 */
	private File exportDataToExcel(File importFile, Map<String, List<ExpressDetail>> dataMap) {

		// 根据上传的原始excel文件, 得到需要导出的文件名
		File exportExcelFile = getExportFile(importFile);

		// 创建导出的excel文件并定义excel文件中相应的样式等信息
		Map<String, Object> excelFileInfoMap = createExportExcelFile(exportExcelFile);

		// 遍历读取到的内容,并逐个写入excel文件
		dataMap.entrySet().forEach(entry -> {

			// 单个sheet的名称
			String sheetName = entry.getKey();
			// 单个Sheet的数据对象
			List<ExpressDetail> expressDetailList = entry.getValue();
			log.info("本次读取后待转换的单个sheet[{}]的数据为: {}", sheetName, JSON.toJSONString(expressDetailList));

			if (!BeanUtils.isNull(expressDetailList)) {
				for (ExpressDetail expressDetail : expressDetailList) {
					BeanUtils.copyProperties(
							expressDetailService.getExpressDetailByData(expressDetail.getExpressCompany(), expressDetail.getExpressNo()), expressDetail);
				}
				log.info("本次转换后待写入Sheet[{}]的数据为: {}", sheetName, JSON.toJSONString(expressDetailList));

				// 将数据写入exce
				exportDataToExcel(sheetName, excelFileInfoMap, exportExcelFile, expressDetailList);
			}
		});

		return exportExcelFile;
	}

	/**
	 * 根据上传的原始excel文件, 得到需要导出的文件名
	 *
	 * @param importFile 源数据文件
	 * @return 结果文件
	 */
	private File getExportFile(File importFile) {
		// 根据导入的文件获取相应的需要导出的文件名称
		String exportFileName = importFile.getParent() + File.separator +
				FilenameUtils.getBaseName(importFile.getAbsolutePath()) + "_" +
				DateUtils.getCurrTime("yyyyMMddhhmmss") + "." +
				FilenameUtils.getExtension(importFile.getName());

		return new File(exportFileName);
	}

	/**
	 * 创建导出的excel文件并定义excel文件中相应的样式等信息
	 *
	 * @param exportExcelFile excel文件名
	 * @return excel文件信息
	 */
	private Map<String, Object> createExportExcelFile(File exportExcelFile) {

		Map<String, Object> excelMap = Maps.newHashMap();

		/* 创建excel文件 */
		try {
			if (!exportExcelFile.exists()) {
				exportExcelFile.createNewFile();
			}
		} catch (IOException e) {
			throw new LogisticsException(ResultEnum.CREATE_EXCEL_FILE_ERROR);
		}

		/* 创建excel工作簿 */
		Workbook workbook;
		if (ExcelUtils.isExcel2007(exportExcelFile.getName())) {
			workbook = new XSSFWorkbook();
		} else {
			workbook = new HSSFWorkbook();
		}

		/* 创建字体样式 */
		Font headerFont = workbook.createFont();
		// 字体加粗
		headerFont.setBold(true);
		// 设置颜色
		headerFont.setColor((short) 8);
		// 设置字体
		headerFont.setFontName("宋体");
		// 设置字体大小
		headerFont.setFontHeightInPoints((short) 18);

		/* 设置导出excel的样式 */
		// 创建标题样式
		CellStyle headerStyle = workbook.createCellStyle();
		// 设置水平居左
		headerStyle.setAlignment(HorizontalAlignment.CENTER);
		// 设置垂直居中
		headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		// 为标题样式设置字体样式
		headerStyle.setFont(headerFont);

		// 创建标题样式
		CellStyle bodyStyle = workbook.createCellStyle();
		// 设置水平居左
		bodyStyle.setAlignment(HorizontalAlignment.LEFT);
		// 设置垂直居中
		bodyStyle.setVerticalAlignment(VerticalAlignment.CENTER);

		// 定义表头
		String[] title = {"序号", "快递公司", "快递单号", "快递状态", "物流轨迹"};

		excelMap.put("workbook", workbook);
		excelMap.put("headerFont", headerFont);
		excelMap.put("headerStyle", headerStyle);
		excelMap.put("bodyStyle", bodyStyle);
		excelMap.put("title", title);
		return excelMap;
	}

	/**
	 * @param expressDetailList 需要写入的数据
	 * @param exportExcelFile   写入后的文件路径
	 * @return 写入数据后的excel文件
	 * 将物流信息写入excel文件
	 */
	private File exportDataToExcel(String sheetName, Map<String, Object> excelFileInfoMap, File exportExcelFile, List<ExpressDetail> expressDetailList) {

		// 得到excel工作簿
		Workbook workbook = (Workbook) excelFileInfoMap.get("workbook");
		// 得到字体样式
		Font headerFont = (Font) excelFileInfoMap.get("headerFont");
		// 得到标题样式
		CellStyle headerStyle = (CellStyle) excelFileInfoMap.get("headerStyle");
		// 得到内容样式
		CellStyle bodyStyle = (CellStyle) excelFileInfoMap.get("bodyStyle");
		// 定义表头
		String[] title = (String[]) excelFileInfoMap.get("title");

		// 得到工作表sheet
		Sheet sheet = workbook.createSheet(sheetName);

		// 创建第一行
		Row row = sheet.createRow(0);
		// 创建第一行数据的表头
		Cell cell;
		for (int i = 0; i < title.length; i++) {
			// 设置每个单元格的宽度
			if (i == title.length - 1) {
				sheet.setColumnWidth(i, 100 * 256);
			} else {
				sheet.setColumnWidth(i, 25 * 256);
			}

			// 创建单元格并赋值
			cell = row.createCell(i);
			cell.setCellValue(title[i]);
			cell.setCellStyle(headerStyle);
		}

		// 写入具体数据
		int rowNum = 1;
		for (ExpressDetail expressDetail : expressDetailList) {
			// 创建具体的数据行
			Row nrow = sheet.createRow(rowNum);
			// 创建具体数据行的单元格并赋值
			Cell ncell = nrow.createCell(0);
			ncell.setCellValue("" + rowNum);

			ncell = nrow.createCell(1);
			ncell.setCellValue("" + expressDetail.getExpressCompany());

			ncell = nrow.createCell(2);
			ncell.setCellValue("'" + expressDetail.getExpressNo());

			ncell = nrow.createCell(3);
			ncell.setCellValue("" + expressDetail.getState());

			// 物流轨迹信息
			ncell = nrow.createCell(4);
			StringBuilder sb = new StringBuilder();
			List<ExpressData> expressDataArr = expressDetail.getExpressDataArray();
			for (ExpressData expressData : expressDataArr) {
				sb.append(expressData.getAcceptStation())
						.append("\t")
						.append(expressData.getRemark())
						.append("\t")
						.append(expressData.getAcceptTime())
						.append("\r\n");
			}
			ncell.setCellValue("" + sb.toString());

			if (!ListUtils.isNull(expressDataArr)) {
				// 设置行高
				nrow.setHeightInPoints(100);
			}
			ncell.setCellStyle(bodyStyle);
			rowNum++;
		}

		// 将数据写入excel
		try {
			FileOutputStream stream = FileUtils.openOutputStream(exportExcelFile);
			workbook.write(stream);
			stream.close();
		} catch (IOException e) {
			throw new LogisticsException(ResultEnum.READ_EXCEL_FILE_ERROR);
		}

		return exportExcelFile;
	}
}